package com.bnzj.cloud.auth.controller;

import com.bnzj.cloud.auth.contans.LoginErrorEnum;
import com.bnzj.cloud.auth.utils.RandomUtil;
import com.bnzj.cloud.auth.utils.SMSVerificationUtil;
import com.bnzj.cloud.business.core.persistence.entity.SysUser;
import com.bnzj.cloud.business.core.service.SysUserService;
import com.bnzj.core.exception.BusinessException;
import com.bnzj.core.rest.ResponseResult;
import com.bnzj.core.util.DateUtils;
import com.bnzj.core.util.SymmetricEncrypt;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.mail.MailSendException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author Barry
 * @createDate 2020/3/6
 * @description
 */
@Tag(name = "登录用户管理")
@RestController
@RequestMapping("/system/login/user")
public class UserController {


    @Autowired
    private SysUserService sysUserService;

    @Resource
    private JavaMailSender javaMailSender;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    //通过邮箱修改Miami


    //通过邮箱修改密码存储前缀
    protected final String FORGET_PREFIX = "FORGET_";

    @Autowired
    private PasswordEncoder passwordEncoder;


    /**
     * @param account 员工工号
     * @return com.bnzj.core.rest.ResponseResult
     * @depict
     * @auth Barry
     * @createDate 2020/3/4
     * @updateAuthOrOther
     */
    @Operation(summary = "发送验证邮箱", description = "发送验邮箱")
    @GetMapping("/forget/thirdly/{account}")
    public ResponseResult<?> thirdly(@PathVariable("account") String account, HttpServletRequest request) {
        //验证用户
        SysUser sysUser = sysUserService.eagerlyFindByAccount(account);
        if (ObjectUtils.isEmpty(sysUser)) {
            throw new BusinessException("用户不存在！", "" + LoginErrorEnum.RECORD_NOT_EXIST.getCode());
        }
        if (ObjectUtils.isEmpty(sysUser.getEmail())) {
            throw new BusinessException("用户邮箱为空,请完善信息！", "" + LoginErrorEnum.RECORD_NOT_EXIST.getCode());
        }
        String token = account + "|||" + System.currentTimeMillis();
        stringRedisTemplate.opsForValue().set(FORGET_PREFIX + account, token, 30, TimeUnit.MINUTES);
        token = SymmetricEncrypt.encryptAES(token);
        if (null == token) {
            throw new BusinessException("加密失败！", LoginErrorEnum.TOKEN_VERIFICATION_ERROR.getCode() + "");
        }
        String origin = request.getHeader("Origin");
        try {
            sendMail(sysUser.getEmail(), token, origin);
        } catch (MailSendException e) {
            throw new BusinessException("发送邮件失败!", LoginErrorEnum.MAIL_FAILED.getCode() + "");
        }
        return ResponseResult.success();
    }


    @Operation(summary = "验证通过,修改密码", parameters = {@Parameter(name = "token", description = "token验证信息"),
            @Parameter(name = "password", description = "新密码")})
    @PostMapping(value = "/forget/fourthly")
    public ResponseResult<?> fourthly(@RequestBody Map<String, String> params) {
        if (ObjectUtils.isEmpty(params.get("token")) || ObjectUtils.isEmpty(params.get("password"))) {
            throw new BusinessException(LoginErrorEnum.PARAMETER_CANNOT_BE_EMPTY.getMessage(), "" + LoginErrorEnum.PARAMETER_CANNOT_BE_EMPTY.getCode());
        }
        String code = params.get("token");
        String _token = SymmetricEncrypt.decryptAES(code);
        if (_token == null) {
            throw new BusinessException("验证失败，请重试！", LoginErrorEnum.TOKEN_VERIFICATION_ERROR.getCode() + "");
        }
        String[] arr = _token.split("\\|\\|\\|");
        //从redis中获取token
        String redis_token = stringRedisTemplate.opsForValue().get(FORGET_PREFIX + arr[0]);
        if (StringUtils.isEmpty(redis_token)) {
            throw new BusinessException("验证信息失效，请重新发送邮件！", LoginErrorEnum.TOKEN_VERIFICATION_ERROR.getCode() + "");
        }
        if (!StringUtils.equals(_token, redis_token.toString())) {
            throw new BusinessException("验证失败，请重试！", LoginErrorEnum.TOKEN_VERIFICATION_ERROR.getCode() + "");
        }
        String password = passwordEncoder.encode(params.get("password"));
        //从redis中删除token 只能使用一次
        stringRedisTemplate.delete(FORGET_PREFIX + arr[0]);
        sysUserService.updatePassword(password, arr[0]);
        return ResponseResult.success();
    }

    @Operation(summary = "验证忘记密码链接是否失效")
    @PostMapping("forget/secondly")
    public ResponseResult<?> verifyThatTheLinkIsBroken(@RequestBody Map<String, String> params) {
        String token = params.get("token");
        String _token = SymmetricEncrypt.decryptAES(token);
        if (_token == null) {
            throw new BusinessException("验证失败，请重试！", LoginErrorEnum.TOKEN_VERIFICATION_ERROR.getCode() + "");
        }
        String[] arr = _token.split("\\|\\|\\|");
        //从redis中获取token
        String redis_token = stringRedisTemplate.opsForValue().get(FORGET_PREFIX + arr[0]);
        if (ObjectUtils.isEmpty(redis_token)) {
            throw new BusinessException("验证信息失效，请重新发送邮件！", LoginErrorEnum.TOKEN_VERIFICATION_ERROR.getCode() + "");
        }
        if (!StringUtils.equals(_token, redis_token.toString())) {
            throw new BusinessException("验证失败，请重试！", LoginErrorEnum.TOKEN_VERIFICATION_ERROR.getCode() + "");
        }
        return ResponseResult.success();
    }


    /**
     * 发送验证邮件
     *
     * @param
     * @return
     */
    @Async
    boolean sendMail(String to, String code, String url) {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
        String date = DateUtils.formatDate(Calendar.getInstance(), "yyyy-MM-dd");
        String subject = "百年智教育系统验证邮件";
//        String url = SpringUtils.getProperty("app.server.host.url") + "/forget/fourthly/" + code;
        try {
            code = URLEncoder.encode(code, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        url = url + "/login?ticket=" + code;
        String html = "<div><a href=\"" + url + "\">按此修改密码</a> 30分钟内有效，发送时间为：" + date + "</div>";
        try {
            messageHelper.setTo(to);
            messageHelper.setSubject(subject);
            //todo 邮箱带更改
            messageHelper.setFrom("homs@bnzj.com.cn");
            messageHelper.setText(html, true);
            javaMailSender.send(mimeMessage);
            return true;
        } catch (MessagingException e) {
            e.printStackTrace();
            return false;
        }
    }

    @GetMapping({"/send/{phone}"})
    public ResponseResult<String> code(@PathVariable String phone) {
        String code = this.redisTemplate.opsForValue().get(phone);
        if (!StringUtils.isEmpty(code)) {
            return ResponseResult.success();
        } else {
            code = RandomUtil.getFourBitRandom();
            Map<String, Object> param = new HashMap();
            param.put("code", code);
            boolean isSend = SMSVerificationUtil.send(phone, "SMS_17", param);
            if (isSend) {
                this.redisTemplate.opsForValue().set(phone, code, 5L, TimeUnit.MINUTES);
                return ResponseResult.success(code);
            } else {
                return ResponseResult.failure(0, "短信验证失败");
            }
        }
    }


    @PostMapping("/authForPhone")
    public ResponseResult authForPhoneLogin(String phone, String code, HttpServletResponse response){
        String redisCode = this.redisTemplate.opsForValue().get(phone);
        ResponseResult result ;
        if(redisCode != null && redisCode.equals(code)){
            String phoneToken = UUID.randomUUID().toString();
            response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
            Map<String, String> accessToken = new HashMap<>();
            accessToken.put("access_token", phoneToken);
            try {
                this.redisTemplate.opsForValue().set(phoneToken, phone, 6000, TimeUnit.SECONDS);
                result = ResponseResult.success(accessToken);
            }catch (Exception e){
                e.printStackTrace();
                result = ResponseResult.failure(500, "服务繁忙！", null);
            }
        }else{
            result = ResponseResult.bizException(new BusinessException( "登录失败！", 10401));
        }
        return result;
    }

}
